/*
 * Copyright (C) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.jama.carouselview.views;

import ohos.agp.animation.AnimatorProperty;
import ohos.agp.components.*;
import ohos.agp.components.Component.DraggedListener;
import ohos.agp.utils.Point;
import ohos.agp.window.service.Display;
import ohos.agp.window.service.DisplayManager;
import ohos.app.Context;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;

/**
 * 自定义ListContainer，应当作为嵌套ListContainer的外层ListContainer，已解决滑动冲突（不同方向）
 *
 * @since 2021-04-19
 */
public class CarouselView extends ListContainer implements DraggedListener, ListContainer.ItemLongClickedListener {
    private static final String TAG = CarouselView.class.getSimpleName();
    private static final HiLogLabel LOG_LABEL = new HiLogLabel(0, 0, "CarouselView");
    private static final int NUM_3 = 3;
    private static final int NUM_250 = 250;
    private static final int NUM_100 = 250;
    private static final float FLOAT_11 = 1.1f;
    private float startX;
    private Display display;
    private boolean isFlag = true;
    private int lastViewPos = 1;

    /**
     * BaseDependentLayout的构造方法，在Java类中new时调用
     *
     * @param context
     */
    public CarouselView(Context context) {
        super(context);
        init(context);
    }

    /**
     * BaseDependentLayout的构造方法，在xml布局中
     *
     * @param context
     * @param attrSet
     */
    public CarouselView(Context context, AttrSet attrSet) {
        super(context, attrSet);
        init(context);
    }

    /**
     * BaseDependentLayout的构造方法，在xml布局且加Style时调用
     *
     * @param context
     * @param attrSet
     * @param styleName
     */
    public CarouselView(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);
        init(context);
    }

    private void init(Context context) {
        setDraggedListener(DRAG_HORIZONTAL, this);
        display = DisplayManager.getInstance().getDefaultDisplay(context).get();
        int firstVisibleItemPosition = getFirstVisibleItemPosition();
        toChangeViewBig(firstVisibleItemPosition);
        postLayout();
        invalidate();
        setItemLongClickedListener(this);
        setLongClickable(false);
    }

    /**
     * onDragDown
     *
     * @param component component
     * @param dragInfo  dragInfo
     */
    @Override
    public void onDragDown(Component component, DragInfo dragInfo) {
    }

    /**
     * onDragStart
     *
     * @param component component
     * @param dragInfo  dragInfo
     */
    @Override
    public void onDragStart(Component component, DragInfo dragInfo) {
        Point downPoint = dragInfo.startPoint;
        startX = downPoint.getPointX();
        clearScaleX(lastViewPos);
        clearAll();
    }

    /**
     * onDragUpdate
     *
     * @param component component
     * @param dragInfo  dragInfo
     */
    @Override
    public void onDragUpdate(Component component, DragInfo dragInfo) {
        scrollBy((int) -dragInfo.xOffset, 0);
    }

    /**
     * onDragEnd
     *
     * @param component component
     * @param dragInfo  dragInfo
     */
    @Override
    public void onDragEnd(Component component, DragInfo dragInfo) {

        Point downPoint = dragInfo.updatePoint;
        float mDownX = downPoint.getPointX();
        float gap = startX - mDownX;
        int lastVisibleItemPosition = getLastVisibleItemPosition();
        if (gap < 0) {
            changeGap(gap);

        } else if (gap > 0) {
            int itemIndex = getFirstVisibleItemPosition();

            if (gap > NUM_250) {
                itemIndex++;
            }

            if (itemIndex == 1) {
                scrollTo(2);
                clearAll();
                toChangeViewBig(itemIndex);
            }
            if (itemIndex == 2) {
                scrollTo(NUM_3);
                toChangeViewBig(itemIndex);
                clearScaleX(lastVisibleItemPosition);
            }
            if (itemIndex == NUM_3) {
                clearAll();
                toChangeViewBig(2);
                return;

            }
            scrollTo(itemIndex);
            lastViewPos = getFirstVisibleItemPosition();
            clearScaleX(lastViewPos);
            invalidate();
        }

    }

    private void changeGap(float gap) {
        int lastindex = getLastVisibleItemPosition();

        if (lastindex == NUM_3) {
            debug(lastindex + "lastindex == 3");
            scrollTo(2);
            clearAll();
            toChangeViewBig(1);
        }
        if (lastindex == 2) {
            scrollTo(0);
            clearAll();
            toChangeViewBig(0);
            debug(lastindex + "lastindex == 2");
        }
        if (lastindex == 1) {
            scrollTo(0);
            clearAll();
            toChangeViewBig(0);
            debug(lastindex + "lastindex == 1");
        }
    }

    /**
     * toChangeViewBig
     *
     * @param firstVisibleItemPosition1 firstVisibleItemPosition1
     */
    public void toChangeViewBig(int firstVisibleItemPosition1) {
        if (firstVisibleItemPosition1 < 0) {
            return;
        }
        Component firstComponent = getComponentAt(firstVisibleItemPosition1);
        AnimatorProperty property = new AnimatorProperty(firstComponent);
        property.scaleX(FLOAT_11);
        property.scaleY(FLOAT_11);
        property.start();
        postLayout();

    }

    private void clearAll() {
        int count = getItemProvider().getCount();
        for (int index = 0; index <= count; index++) {
            Component componentAt = getComponentAt(index);
            AnimatorProperty property = new AnimatorProperty(componentAt);
            property.scaleX(1);
            property.scaleY(1);
            property.setDuration(NUM_100);
            property.start();
        }
    }

    /**
     * setLongClickable
     *
     * @param longClickable longClickable
     */
    @Override
    public void setLongClickable(boolean longClickable) {
        super.setLongClickable(false);
    }

    /**
     * executeLongClick
     *
     * @return boolean
     */
    @Override
    public boolean executeLongClick() {
        return false;
    }

    private void clearScaleX(int toBigView) {
        if (toBigView < 0) {
            return;
        }
        Component componentAt = getComponentAt(toBigView);
        AnimatorProperty property = new AnimatorProperty(componentAt);
        property.scaleX(1);
        property.scaleY(1);
        property.setDuration(NUM_100);
        property.start();
    }

    /**
     * onDragCancel
     *
     * @param component component
     * @param dragInfo  dragInfo
     */
    @Override
    public void onDragCancel(Component component, DragInfo dragInfo) {
    }

    /**
     * onItemLongClicked
     *
     * @param parent
     * @param component
     * @param position
     * @param id
     * @return boolean
     */
    @Override
    public boolean onItemLongClicked(ListContainer parent, Component component, int position, long id) {
        return true;
    }

    /**
     * setAdapter
     */
    public void setAdapter() {
        getItemProvider().notifyDataChanged();
    }

    /**
     * getScrooll
     *
     * @return boolean
     */
    public boolean getScrooll() {
        return isFlag;
    }



    /**
     * validate
     */
    public void validate() {
        invalidate();
    }

    /**
     * show
     */
    public void show() {
        this.validate();
        this.setAdapter();
    }

    /**
     * hideIndicator
     *
     * @param flag flag
     * @return boolean
     */
    public boolean hideIndicator(boolean flag) {
        if (flag) {
            setVisibility(HIDE);
        } else {
            setVisibility(VISIBLE);
        }
        return true;
    }

    private void debug(String msg) {
        HiLog.error(LOG_LABEL, msg);
    }
}